package com.tarena.luban.demo.gateway.filters;

import com.alibaba.nacos.common.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Supplier;

//@Component
@Slf4j
public class MyFilter01 implements GlobalFilter, Ordered {
    //网关过滤器的 核心过滤方法 如果这个过滤器生效,这个filter方法一定执行

    /**
     * @param exchange 交换机 是一个包含了当前请求响应对象的数据封装
     * @param chain 过滤链对象 连接前后过滤器的关键数据
     * @return Mono 底层spring web flux的数据对象 类似于springmvc controller中 Model
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("当前过滤器myfilter01执行了过滤逻辑");
        //让请求数据 在当前过滤器处理完毕后,向下交给后方的其它流程
        //读取请求中的携带数据,需要先拿到请求对象,在exchange中包装
        //1. 拿到过滤器中 请求对象
        ServerHttpRequest request = exchange.getRequest();
        //2. 获取请求路径 path /stock/hello URL地址 http://localhost:10000/stock/hello?name=**
        RequestPath path = request.getPath();
        URI uri = request.getURI();
        log.info("请求path:{}",path);
        log.info("请求uri:{}",uri);
        //3. 请求参数 get请求 url参数 query 格式 ?name=wch&name=lsf&age=18
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        //参数携带有几个情况 第一种 参数为空 第二种 参数的值为空 第三种 参数有值
        //?age=18 nameParams对象是空的
        //?name&age=18 nameParams对象不是null 但是size=0
        //?name=wch nameParams 不是null size=1 唯一的元素就是wch
        List<String> nameParams = queryParams.get("name");
        if (CollectionUtils.isNotEmpty(nameParams)){
            log.info("name参数值:{}",nameParams);
        }else{
            log.info("name参数值为空");
        }
        //4.获取请求头
        HttpHeaders headers = request.getHeaders();
        InetSocketAddress host = headers.getHost();
        List<String> accept = headers.get("Accept");
        log.info("accept头:{}",accept);
        log.info("host头:{}",host);
        log.info("accept头元素个数:{}",accept.size());
        List<MediaType> accept1 = headers.getAccept();
        log.info("封装的accept元素个数:{}",accept1.size());
        //5.请求cookie
        MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        if (cookies.isEmpty()){
            log.info("cookie值空");
        }
        //请求cookie格式
        //Cookie: cookieName1=value1;cookieName2=value2;cookieName2=value3
        //6.请求客户端地址
        InetSocketAddress remoteAddress = request.getRemoteAddress();
        log.info("当前访问网关客户端ip:{},hostName:{}",remoteAddress.getAddress(),remoteAddress.getHostName());
        //MultiValueMap的数据格式 key值是string name age
        //value值是List<String> name=[wch,lsf] age=[18]

        //使用响应对象 可以直接输出数据
        String message="你被过滤器拦截了";
        ServerHttpResponse response = exchange.getResponse();
        //输出任何中文字符串数据,要先处理乱码问题 设置一个响应头
        //Content-Type: application/json;chartset=utf-8 绝大多数浏览器看到这个头,默认直接使用utf-8 除了微软默认浏览器
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        //1.响应对象要携带这个字符串,需要携带流数据 buffer流缓冲流
        DataBufferFactory factory = response.bufferFactory();
        DataBuffer dataBuffer = factory.wrap(message.getBytes(StandardCharsets.UTF_8));
        //2.创建一个response可以输出的对象 dataBuffer做包装
        Mono<DataBuffer> writeResult =
                Mono.fromSupplier(new Supplier<DataBuffer>() {
                    @Override
                    public DataBuffer get() {
                        return dataBuffer;
                    }
                });
        //3. 响应要输出的数据 整理好后,直接输出
        return response.writeWith(writeResult);
        //response.writeWith(Mono.fromSupplier(() -> response.bufferFactory().wrap(message.getBytes(StandardCharsets.UTF_8))));
    }

    //多个过滤器执行顺序有关

    /**
     * @return 定义过滤器执行顺序的数字 数字越小 过滤器执行顺序越靠前
     * -21亿 ~ 21亿 int有符号的整数区间
     * Integer.MAX_VALUE
     * Integer.MIN_VALUE
     * 100 200 300 400 500... 有步数 step=100
     */
    @Override
    public int getOrder() {
        return 10000;
    }
}
